﻿namespace Vibstudio.NetConfigurator.Engine.Configuration
{
    #region Namespaces

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Reflection;
    using System.Xml.Linq;

    using Vibstudio.NetConfigurator.Common;
    using Vibstudio.NetConfigurator.Exceptions;
    using Vibstudio.NetConfigurator.Extensions;
    using Vibstudio.NetConfigurator.Model;

    #endregion

    [Obfuscation(Exclude = true, ApplyToMembers = false)]
    internal class HttpConfigurator : IConfiguration
    {
        #region Fields

        private List<ConfigurationSetting> _exceptionsSettings;

        private List<ConfigurationSetting> _overrideSettings;

        private List<ConfigurationSetting> _settings;

        #endregion

        #region Public Methods and Operators

        public bool Configure(string filePath, List<ConfigurationSetting> settings)
        {
            _settings = settings;
            _exceptionsSettings = ConfigurationHelper.GetSettings(_settings, HttpSection.Exceptions);
            _overrideSettings = ConfigurationHelper.GetSettings(_settings, HttpSection.Overrides);

            XDocument document = XDocument.Load(filePath);

            bool configured = ChangeServiceHost(document);
            if (configured)
            {
                document.Save(filePath);
            }

            return configured;
        }

        public void Reset()
        {
            throw new NotImplementedException();
        }

        #endregion

        #region Methods

        private bool ChangeServiceHost(XDocument document)
        {
            try
            {
                IEnumerable<XAttribute> attributes =
                    from e in document.Elements().Descendants().Attributes()
                    where e.Value.StartsWith("http")
                    select e;

                foreach (XAttribute attribute in attributes)
                {
                    string previousValue = string.Empty;
                    string value = attribute.Value;

                    if (attribute.PreviousAttribute != null)
                    {
                        previousValue = attribute.PreviousAttribute.Value.ToLower();
                    }

                    if (previousValue.Contains("base"))
                    {
                        attribute.SetValue(GetUpdatedUrl(value, HttpSection.Aspnet));
                    }
                    else
                    {
                        if (value.IsAspnetUrl())
                        {
                            attribute.SetValue(GetUpdatedUrl(value, HttpSection.Aspnet));
                        }

                        if (!value.IsAspnetUrl())
                        {
                            attribute.SetValue(GetUpdatedUrl(value, HttpSection.Java));
                        }
                    }
                }

                IEnumerable<XElement> elements =
                    from e in document.Elements().Descendants()
                    where e.Name == "value" && e.Value.StartsWith("http")
                    select e;

                foreach (XElement element in elements)
                {
                    string value = element.Value;

                    if (value.IsAspnetUrl())
                    {
                        element.SetValue(GetUpdatedUrl(value, HttpSection.Aspnet));
                    }

                    if (!value.IsAspnetUrl())
                    {
                        element.SetValue(GetUpdatedUrl(value, HttpSection.Java));
                    }
                }
            }
            catch (Exception exception)
            {
                throw new ConfigurationException(exception.Message);
            }

            return true;
        }

        private string GetUpdatedUrl(string url, HttpSection httpSection)
        {
            string updatedUrl;
            string host = string.Empty;
            string actualHost = url.GetHost();

            bool isExceptionHost =
                _exceptionsSettings.Exists(s => s.Value.ToLower() == actualHost.ToLower());

            if (!isExceptionHost)
            {
                List<ConfigurationSetting> settings = ConfigurationHelper.GetSettings(_settings, httpSection);

                foreach (
                    ConfigurationSetting setting in settings
                        .Where(setting => !string.IsNullOrEmpty(setting.Key))
                        .Where(setting => url.ToLower().Contains(setting.Key.ToLower())))
                {
                    host = setting.Value;
                    break;
                }

                if (string.IsNullOrEmpty(host))
                {
                    foreach (ConfigurationSetting setting in settings)
                    {
                        if (string.IsNullOrEmpty(setting.Key))
                        {
                            host = setting.Value;
                            break;
                        }
                    }
                }

                updatedUrl = url.ReplaceHost(host);

                string resourceName = url.GetResourceName();
                if (!string.IsNullOrEmpty(resourceName))
                {
                    bool isOverridable = _overrideSettings.Exists(o => o.Key.ToLower() == resourceName.ToLower());

                    if (isOverridable)
                    {
                        string replacement =
                            _overrideSettings.Find(o => o.Key.ToLower() == resourceName.ToLower()).Value;
                        updatedUrl = updatedUrl.ReplaceResourceName(replacement);
                    }
                }
            }
            else
            {
                updatedUrl = url;
            }

            return updatedUrl;
        }

        #endregion
    }
}